/*
 * mythread.h -- interface of user threads library
 */

#ifndef MYTHREAD_H
#define MYTHREAD_H

#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif

#include <setjmp.h>
#include "myqueue.h"

typedef struct mythread_attr {    /* thread attributes */
	int stacksize;                  /* stack size in bytes */
} mythread_attr_t;

typedef struct mythread {         /* thread control block */
	int state;                      /* state of execution */
	void * (*start_func)(void*);    /* thread_func to be called */
	void *arg;                      /* thread_arg arguments of thread_func */
	mythread_queue_t joinq;         /* Q of threads waiting for my return */
	jmp_buf context;                /* save area for context switches */
	void *returnValue;              /* Pointer to the detached function's return value */
    int read_fd;                    /* async read file desc */
} *mythread_t;

/*
 * mythread_self - thread id of running thread
 */
mythread_t mythread_self(void);

/*
 * swap context from oth to nth
 */
int myswapcontext(sigjmp_buf *oth, sigjmp_buf *nth);

/*
 * mythread_block - remove currently running thread off run q (if present),
 * if q is non-NULL and, enq this thread on q,
 * always suspend the thread,
 * add the state flags to the thread's state (via bit-wise OR | state)
 */
void mythread_block(mythread_queue_t *q, int state);

/*
 * mythread_unblock_thread - resumes a thread in a q,
 * remove the state flags to the thread's state (via bit-wise AND & ~state)
 * and activate the thread
 */
void mythread_unblock_thread(mythread_queue_t *q, mythread_t current, int state);

/*
 * mythread_unblock - resumes the thread at the head of q,
 * remove the state flags to the thread's state (via bit-wise AND & ~state)
 * and activate the thread
 */
void mythread_unblock(mythread_queue_t *q, int state);

/*
 * mythread_create - prepares context of new_thread_ID as start_func(arg),
 * attr is ignored right now.
 * Threads are activated (run) according to the number of available LWPs
 * or are marked as ready.
 */
int mythread_create(mythread_t *new_thread_ID,
					mythread_attr_t *attr,
					void * (*start_func)(void *),
					void *arg);

/*
 * mythread_yield - switch from running thread to the next ready one
 */
int mythread_yield(void);

/*
 * mythread_join - suspend calling thread if target_thread has not finished,
 * enqueue on the join Q of the target thread, then dispatch ready thread;
 * once target_thread finishes, it activates the calling thread / marks it
 * as ready.
 */
int mythread_join(mythread_t target_thread, void **status);

/*
 * mythread_exit - exit thread, awakes joiners on return
 * from thread_func and dequeue itself from run Q before dispatching run->next
 */
void mythread_exit(void *retval);

#endif /* MYTHREAD_H */
